using System;
using System.Collections.Generic;
using System.Collections;
using Microsoft.Xna.Framework;

using Core.Mapping;
using Core.Graphics;

namespace WorldEditor
{
    public class ContiguousTiles
    {
        static ArrayList Points;

        static ArrayList _Next;
        static ArrayList _Current;

        static TileWorld _World;
        static Tile _ReplaceTile;
        static Point _StartPoint;
        static MapLayerTypes _LayerType;

        public static ArrayList ContiguousTileFinder(TileWorld World, Point startpoint, MapLayerTypes LayerType)
        {
            Points = new ArrayList();
            _World = World;
            _LayerType = LayerType;
            _StartPoint = startpoint;
            _ReplaceTile = _World.GetTileAtLocation(startpoint, _LayerType);
            Find();

            return Points;
        }

        private static void Find()
        {
            _Next = new ArrayList();

            CheckUpDown(_StartPoint);
            CheckLineFromPoint(_StartPoint);
            //While there are tiles waiting to be found
            while (_Next.Count > 0)
            {
                //Move Next to Current
                _Current = _Next;
                //Create new Next
                _Next = new ArrayList();
                //For each point in Current
                foreach (Point pt in _Current)
                {
                    CheckUpDown(pt);
                    //Check all lines from there.
                    CheckLineFromPoint(pt);
                }
            }
        }

        private static void CheckLineFromPoint(Point pt)
        {
            //Fill initial spot
            if(!Points.Contains(pt))
                Points.Add(pt);
            //Create poiints representing the points left and right of this point
            Point left = new Point(pt.X - 1, pt.Y);
            Point right = new Point(pt.X + 1, pt.Y);
            //While we are not past the left edge of the layer
            while (IsPointInConstraintBounds(left))
            {
                //get the tile at that location
                Tile tmap = _World.GetTileAtLocation(left, _LayerType);
                //If this tile is a tile we are searching for add it
                if (tmap.SpriteID == _ReplaceTile.SpriteID && !Points.Contains(left))
                {
                    Points.Add(left);
                    _Next.Add(left);

                    CheckUpDown(left);
                }
                //If it's not a tile we are replacing then this line is broken and we break;
                else
                {
                    break;
                }
                //Increment
                left.X--;
            }

            while (IsPointInConstraintBounds(right))
            {
                Tile tl = _World.GetTileAtLocation(right, _LayerType);

                if (tl.SpriteID == _ReplaceTile.SpriteID && !Points.Contains(right))
                {
                    Points.Add(right);
                    _Next.Add(right);
                    CheckUpDown(right);
                }
                else
                {
                    break;
                }

                right.X++;
            }
        }

        private static void CheckUpDown(Point pt)
        {
            Point up = new Point(pt.X, pt.Y + 1);
            Point down = new Point(pt.X, pt.Y - 1);

            CheckPoint(up); CheckPoint(down);
        }

        /// <summary>
        /// Checks to see if the tile at the point matches the tile we are replacing.  If it does it adds it to 
        /// the Next batch.
        /// </summary>
        /// <param name="pt">Point to Check</param>
        private static void CheckPoint(Point pt)
        {
            if (!IsPointInConstraintBounds(pt))
                return;

            Tile t = _World.GetTileAtLocation(pt, _LayerType);

            if (t.SpriteID == _ReplaceTile.SpriteID && !Points.Contains(pt))
            {
                Points.Add(pt);
                _Next.Add(pt);
            }
        }

        private static bool IsPointInConstraintBounds(Point pt)
        {
            if (pt.X >= 0 && pt.X < _StartPoint.X + 64 && pt.X > _StartPoint.X - 64 
                && pt.Y >= 0 && pt.Y < _StartPoint.Y + 64 && pt.Y > _StartPoint.Y - 64)
                return true;
            else
                return false;
        }
    }
}
